package com.example.demo.controller;

import com.example.demo.service.TransactionServiceA;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName SpringTransactionController
 * @Author bsy
 * @Description
 * 参考原文：https://mp.weixin.qq.com/s/T1miQijU_6yVXfQFAH2oAA
 *
 * 问题一：神魔是事务
 *
 * 问题二：事务传播机制
 * Spring 事务中定义了 7 种事务传播类型，分别是：REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。
 * 其中最常用的只有 3 种，即：
 * REQUIRED、REQUIRES_NEW、NESTED。
 *
 * REQUIRED：传播类型，它是父子方法共用同一个事务的
 * REQUIRES_NEW：父子方法的事务是独立的，不相互影响， 但是父方法需要注意子方法抛出的异常，避免因子方法抛出异常，而导致父方法回滚。因为如果执行过程中发生 RuntimeException 异常和 Error 的话，那么 Spring 事务是会自动回滚的
 * 针对事务传播类型，我们要弄明白的是 4 个点：
 *  NESTED：在子方法事务发生异常回滚时，当前方法存在事务时，子方法加入在嵌套事务执行。当父方法事务回滚时，子方法事务也跟着回滚。当子方法事务发送回滚时，父事务是否回滚取决于是否捕捉了异常。如果捕捉了异常，那么就不回滚，否则回滚
 *  父方法有着不同的反应动作
 * 1、子事务与父事务的关系，是否会启动一个新的事务？
 * 2、子事务异常时，父事务是否会回滚？
 * 3、父事务异常时，子事务是否会回滚？
 * 4、父事务捕捉异常后，父事务是否还会回滚？
 *
 *
 *
 * 问题三：使用 Spring 事务的步骤为：
 *
 * 根据业务场景，分析要达成的事务效果，确定使用的事务传播类型。
 * 在 Service 层使用 @Transaction 注解，配置对应的 propogation 属性。
 *
 *
 * 问题四：Spring 事务失效
 * 什么时候 Spring 事务会失效？
 * 若同一类中的其他没有 @Transactional 注解的方法内部调用有 @Transactional 注解的方法，有 @Transactional 注解的方法的事务会失效。
 *
 * 这是由于 Spring AOP 代理的原因造成的，因为只有当 @Transactional 注解的方法在类以外被调用的时候，Spring 事务管理才生效。
 *
 * 另外，如果直接调用，不通过对象调用，也是会失效的。因为 Spring 事务是通过 AOP 实现的。
 *
 * @Transactional 注解只有作用到 public 方法上事务才生效。
 *
 * 被 @Transactional 注解的方法所在的类必须被 Spring 管理。
 *
 * 底层使用的数据库必须支持事务机制，否则不生效。
 *
 * @Date 2022/8/25 21:56
 * @Version 1.0
 */

@RestController
@RequestMapping("/api")
public class SpringTransactionController {

    @Autowired
    private TransactionServiceA transactionServiceA;

    @RequestMapping("/spring-transaction")
    public String testTransaction() throws Exception {
        transactionServiceA.methodA();
        return "SUCCESS";
    }
}
